package com.softao.ming.gde.core;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;

import com.softao.ming.gde.core.model.IBundleModel;
import com.softao.ming.gde.core.model.IBundleVersion;
import com.softao.ming.gde.internal.core.GdeCore;
import com.softao.ming.gde.internal.core.model.BundleModelImpl;

/**
 * Finding bundles registered.
 */
public class BundleRegistry {
	private final Map<String, IBundleModel> mBinaryBundles;
	private final Map<String, IBundleModel> mSourceBundles;
	
	/**
	 */
	public BundleRegistry() {
		mBinaryBundles = new HashMap<String, IBundleModel>();
		mSourceBundles = new HashMap<String, IBundleModel>();
	}
	
	/**
	 * @return all bundles registered
	 */
	public IBundleModel[] allBundles() {
		List<IBundleModel> result = new ArrayList<IBundleModel>();
		result.addAll(mBinaryBundles.values());
		result.addAll(mSourceBundles.values());
		return result.toArray(new IBundleModel[result.size()]);
	}
	
	/**
	 * @return all source bundle
	 */
	public IBundleModel[] allSourceBundles() {
		return mSourceBundles.values().toArray(new IBundleModel[mSourceBundles.size()]);
	}
	
	/**
	 * @param rootPath the root path of the platform
	 * @throws CoreException
	 */
	public void registryDirectory(File rootPath) throws CoreException {
		if (!rootPath.isDirectory()) {
			String msg = String.format("%1$s is not a directory.", rootPath);
			GdeCore.getDefault().logWarn(msg, null);
			return;
		}
		
		for (File file : rootPath.listFiles()) {
			registrySingle(file);
		}
	}
	
	/**
	 * @param file the file for the bundle to be registered
	 * @throws CoreException 
	 */
	public void registrySingle(File file) throws CoreException {
		BundleModelImpl bundle;
		try {
			bundle = new BundleModelImpl(file);
		} catch (IOException e) {
			String msg = String.format("File %1$s can not be read.", file);
			IStatus status = new Status(IStatus.ERROR, GdeCore.PLUGIN_ID, msg);
			throw new CoreException(status);
		}
		
		boolean gwtSourceBundle = bundle.getManifestFile().isSourceBundle()
				|| bundle.isGdeProject();
		if (gwtSourceBundle) {
			gwtSourceBundle = bundle.getGwtPluginFile().hasClientCode();
		}
		
		if (gwtSourceBundle) {
			addBundle(mSourceBundles, bundle);
		} else {
			if (bundle.getManifestFile().isSourceBundle()) {
				return; // Source bundle not included.
			}
			addBundle(mBinaryBundles, bundle);
		}
	}
	
	private static final void addBundle(Map<String, IBundleModel> bundles, IBundleModel bundle) {
		String key = bundle.getManifestFile().getBundleUniqueIdentifier();
		if (!bundles.containsKey(key)) {
			bundles.put(key, bundle);
		} else {
			IBundleVersion bundleVersion = bundle.getManifestFile().getBundleVersion();
			IBundleModel existingBundle = bundles.get(key);
			IBundleVersion version2 = existingBundle.getManifestFile().getBundleVersion();
			if (bundleVersion.compareTo(version2) > 0) {
				bundles.put(key, bundle);
			}
		}
	}
}
